use crate::parse::{Field, Struct, Type};

//生成代码
pub fn generate(id: u16, check: u16, parse_struct: &Struct) -> String
{
    let mut out_str = String::new();
    //生成get_id函数
    out_str += &generate_get_id(id);
    //生成get_check函数
    out_str += &generate_get_check(check);
    //生成get_size函数
    out_str += &generate_get_size(&parse_struct.fields);
    //生成to_bytes函数
    out_str += &generate_to_bytes(id, check, &parse_struct.fields);
    //生成form_bytes函数
    out_str += &generate_form_bytes(id, check, &parse_struct.fields);

    //把生成的函数包裹在impl块里面
    out_str = format!("\nimpl {} {{{}\n}}", parse_struct.struct_name, out_str);

    out_str
}

fn generate_get_id(id: u16) -> String
{
    format!("\n    pub fn get_ser_id() -> u16 {{\n        {id}\n    }}")
}
fn generate_get_check(check: u16) -> String
{
    format!("\n    pub fn get_ser_check() -> u16 {{\n        {check}\n    }}")
}
fn generate_get_size(fields: &Vec<Field>) -> String
{
    let mut size: usize = 0;
    let mut body = String::new();
    for field in fields
    {
        //...
        match field.field_type
        {
            Type::I8 => size += 1,
            Type::I16 => size += 2,
            Type::I32 => size += 4,
            Type::I64 => size += 8,
            Type::I128 => size += 16,
            Type::U8 => size += 1,
            Type::U16 => size += 2,
            Type::U32 => size += 4,
            Type::U64 => size += 8,
            Type::U128 => size += 16,
            Type::F32 => size += 4,
            Type::F64 => size += 8,
            Type::Bool => size += 1,
            Type::Char => size += 4,
            Type::Str => body += &format!("\n        size += {}.len();", field.field_name),
            Type::String => body += &format!("\n        size += {}.len();", field.field_name),
            Type::Struct(_) =>
            {
                body += &format!("\n        size += {}.get_ser_len();", field.field_name)
            }
            Type::Box(_) => println!("xx"),
            Type::Vec(_) => println!("xx"),
            Type::Array(_) => println!("xx"),
            Type::Pointer(_) => println!("xx"),
            Type::Reference(_) => println!("xx"),
            _ => println!(""),
        }
    }
    if body.len() > 0
    {
        format!("\n    pub fn get_ser_len(&self) -> u32 {{\n        let len:u32 = {size};{body}\n        len\n    }}")
    }
    else
    {
        format!("\n    pub fn get_ser_len(&self) -> u32 {{\n        {size}\n    }}")
    }
}
fn generate_to_bytes(id: u16, check: u16, fields: &Vec<Field>) -> String
{
    let id_check: u32 = (id as u32) + ((check as u32) << 16);
    let mut body = format!("\n            let p = bytes.as_ptr() as usize;\n            *(p as *mut u32) = {id_check};");
    for field in fields
    {
        //...
        match field.field_type
        {
            Type::I8 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut i8) = self.{};",
                    field.field_name
                )
            }
            Type::I16 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut i16) = self.{};",
                    field.field_name
                )
            }
            Type::I32 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut i32) = self.{};",
                    field.field_name
                )
            }
            Type::I64 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut i64) = self.{};",
                    field.field_name
                )
            }
            Type::I128 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut i128) = self.{};",
                    field.field_name
                )
            }
            Type::U8 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut u8) = self.{};",
                    field.field_name
                )
            }
            Type::U16 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut u16) = self.{};",
                    field.field_name
                )
            }
            Type::U32 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut u32) = self.{};",
                    field.field_name
                )
            }
            Type::U64 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut u64) = self.{};",
                    field.field_name
                )
            }
            Type::U128 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut u128) = self.{};",
                    field.field_name
                )
            }
            Type::F32 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut f32) = self.{};",
                    field.field_name
                )
            }
            Type::F64 =>
            {
                body = format!(
                    "{body}\n            *(p as *mut f64) = self.{};",
                    field.field_name
                )
            }
            Type::Bool =>
            {
                body = format!(
                    "{body}\n            *(p as *mut bool) = self.{};",
                    field.field_name
                )
            }
            Type::String => println!(""),
            Type::Struct(_) => println!(""),
            Type::Box(_) => println!(""),
            Type::Vec(_) => println!(""),
            Type::Array(_) => println!(""),
            _ => println!(""),
        }
    }

    format!("\n    pub fn to_bytes(&self, bytes: &mut [u8]) -> u32 {{\n        let mut byte_count = 4;\n        unsafe {{{body}\n        }}\n        byte_count\n    }}")
}
fn generate_form_bytes(id: u16, check: u16, _fields: &Vec<Field>) -> String
{
    let id_check: u32 = (id as u32) + ((check as u32) << 16);
    let body = "";
    let byte_count = id_check;

    format!(
        "\n    pub fn form_bytes(&self, bytes:&[u8]) -> u32 {{{body}\n        {byte_count}\n    }}"
    )
}
